var WeatherSim = (function(Cesium,$){
	function WeatherSim(_viewer,_center,_radius,styleurl){
		this.weatherSimViewer = _viewer||undefined;
		this.center = _center;
		this.centerCarto = Cesium.Ellipsoid.WGS84.cartesianToCartographic(_center);
		this.radius = _radius;
		this.particleSystem;
		this._currentLocation = getCameraLocation(this.weatherSimViewer.container)||null;
		this._currentGbcode = '';
		this._styleurl=styleurl;
		this._style={};
		//this.gravityAcc = 9.8;
	}
	
	WeatherSim.prototype.loadStyle=function(){
		var that = this;
		$.getJSON(''+that._styleurl, function(data){
			that._style = data;
        }.bind(this));
	}
	
	var gravityAcc = 9.8;
	var rainGravityAcc = 100*gravityAcc;
	WeatherSim.prototype.snow=function(rate){
		var that = this;
		if(Cesium.defined(this.particleSystem)) this.weatherSimViewer.scene.primitives.remove(this.particleSystem);
		var life = Math.sqrt(this.centerCarto.height*2/gravityAcc);
		this.particleSystem = this.weatherSimViewer.scene.primitives.add(new Cesium.ParticleSystem({
			image :'images/snowflake.png',
			//startColor:Cesium.Color.fromHsl(0.66, 1.0, 0.7),
			//endColor:Cesium.Color.fromHsl(0.66, 1.0, 0.7),
			//startScale : 1.0,
			//endScale : 1.0,
			life : life||10.0,
			//speed : 5.0,
			width : 10,
			height : 10,
			rate : rate||50.0,
			lifeTime:300,
			modelMatrix : computeModelMatrix(that.center),
			emitterModelMatrix : computeEmitterModelMatrix(),
			emitter: new Cesium.CircleEmitter(that.radius),
			forces: [applyGravity]
		}));
	}	
	
	WeatherSim.prototype.rain=function(rate,width,height){
		var that = this;
		if(Cesium.defined(this.particleSystem)) this.weatherSimViewer.scene.primitives.remove(this.particleSystem);
		var life = Math.sqrt(this.centerCarto.height*2/rainGravityAcc)+2;
		this.particleSystem = this.weatherSimViewer.scene.primitives.add(new Cesium.ParticleSystem({
			image :'images/raindrop2.png',
			//startColor:Cesium.Color.fromHsl(0.66, 1.0, 0.8),
			//endColor:Cesium.Color.fromHsl(0.66, 1.0, 0.8),
			//startScale : 1.0,
			//endScale : 1.0,
			life : life||10.0,
			//speed : 5.0,
            width : width||3,
			height : height||10,
			rate : rate||50,
			lifeTime:300,
			modelMatrix : computeModelMatrix(that.center),
			emitterModelMatrix : computeEmitterModelMatrix(),
			emitter: new Cesium.CircleEmitter(that.radius),
			forces: [applyForceRain]
		}));
	}
	function getCameraLocation(container){
        var width = container.clientWidth;
        var height = container.clientHeight;
        var offsetTop = container.clientTop;
        var offsetLeft = container.clientLeft;
        var center = new Cesium.Cartesian2(width/2+offsetLeft,height/2+offsetTop);
        var cartesian = viewer.camera.pickEllipsoid(center);
        if(!Cesium.defined(cartesian)) {
            // console.log('center not on globe');
            return null;
        }
        var radians = Cesium.Cartographic.fromCartesian(cartesian);
        var degrees = {
            latitude:Cesium.Math.toDegrees(radians.latitude),
            longitude:Cesium.Math.toDegrees(radians.longitude),
            height:Cesium.Math.toDegrees(radians.height)
        };
        // console.log('getCameraLocation done');
        return degrees;
    };
    /**
     * update current location when camera move end
     */
    WeatherSim.prototype.updateLocation=function(container){
		var that = this;
        viewer.camera.moveEnd.addEventListener(function(){
            that._currentLocation = getCameraLocation(container)||null;//this._currentLocation;
			if(that._currentLocation){
                that.updateWeather(that._currentLocation.longitude,that._currentLocation.latitude,function(data){
                    that.updateStyle(data);
                })
                // console.log('updateLocation done');
			}

        });
    }
	
	WeatherSim.prototype.autoUpdateWeather=function(){
		this.updateLocation(this.weatherSimViewer.container);
	}
	
	WeatherSim.prototype.updateWeather=function(lon,lat,callback){
		var input={"lonlat":''+lon+','+lat,'level':'5'};
        var url= 'http://weather.tianditu.com/weather/changeArea?type=changeCity&postStr='+JSON.stringify(input);
        $.getJSON(url, function(data){
            var name = data.name;
            var gbcode=data.gbcode;
            var parentName = data.parentName;
            var parentGbcode = data.parentGbcode;
            if(name && gbcode && parentName && parentGbcode){
				if(this._currentGbcode!=gbcode){
					this._currentGbcode=gbcode;
					console.log('get new gbcode');
					getWeather(gbcode,parentGbcode,callback);
				}
				else{
					console.log('get old gbcode');
				}
				
            }
            else{
                console.log('not a city');
				//getWeather();
            }
        }.bind(this));
	}

    WeatherSim.prototype.updateStyle = function (data) {
		var indextoday = data.ic[0].slice(1);
		console.log(indextoday);
		var thisStyle = this._style[indextoday];
		var brightnessShift=thisStyle.skyAtmosphere.brightnessShift;
		var saturationShift=thisStyle.skyAtmosphere.saturationShift;
		this.weatherSimViewer.scene.skyAtmosphere.brightnessShift=brightnessShift;
		this.weatherSimViewer.scene.skyAtmosphere.saturationShift=saturationShift;
		if(thisStyle.rate){
			if((thisStyle.id>=3 && thisStyle.id<=12) || thisStyle.id==19||(thisStyle.id>=21 && thisStyle.id<=25)){
				this.rain(thisStyle.rate);
			}
			else if((thisStyle.id>=13 && thisStyle.id<=17) || (thisStyle.id>=26 && thisStyle.id<=28)){
				this.snow(thisStyle.rate);
			}
		}
    }
	
	function getWeather(gbcode,parentGbcode,callback){
		if(!gbcode||!parentGbcode) ;
        var url = 'http://weather.tianditu.com/weather/weathers?gbcode='+gbcode;
        $.getJSON(url, function(data){
            if(data.currentdata.length){
                callback(data.currentdata[0]);
                console.log('getWeather done(current district)');
            }
            else{
                if(parentGbcode=='0') ;
                else{
                    var url2='http://weather.tianditu.com/weather/weathers?gbcode='+parentGbcode;
                    $.getJSON(url2, function(data){
                        if(data.currentdata.length){
                            callback(data.currentdata[0]);
                            console.log('getWeather done(parent district)');
                        }
                        else{
                            console.log('no weather report');
                        }
                    });
                }
            }
        });
	}
	
	function computeModelMatrix(center) {
		var position = center;
		var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position, undefined, new Cesium.Matrix4());    
		return modelMatrix;
	 }

	function computeEmitterModelMatrix() {
		var hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 180.0, 0.0, new Cesium.HeadingPitchRoll());
		var trs = new Cesium.TranslationRotationScale();
		trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, new Cesium.Quaternion());
		return Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4());
	}
	
	var gravityScratch = new Cesium.Cartesian3();
	function applyGravity(p, dt) {
		// Compute a local up vector for each particle in geocentric space.
		var position = p.position;

		Cesium.Cartesian3.normalize(position, gravityScratch);
		Cesium.Cartesian3.multiplyByScalar(gravityScratch, -gravityAcc * dt, gravityScratch);
		p.velocity = Cesium.Cartesian3.add(p.velocity, gravityScratch, p.velocity);
	}
	
	function applyForceRain(p,dt){
		var position = p.position;

		Cesium.Cartesian3.normalize(position, gravityScratch);
		Cesium.Cartesian3.multiplyByScalar(gravityScratch, -rainGravityAcc * dt, gravityScratch);
		p.velocity = Cesium.Cartesian3.add(p.velocity, gravityScratch, p.velocity);
	}
	return WeatherSim;
})(window.Cesium||{},window.$||{});